package net.tv90.bfmccore.game;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.tv90.bfmccore.BFMCCore;
import net.tv90.bfmccore.code.VehicleMenuAssets;
import net.tv90.bfmccore.game.impl.ConquestGame;
import net.tv90.bfmccore.game.impl.FrontLineGame;
import net.tv90.bfmccore.game.impl.TDMGame;
import net.tv90.bfmccore.game.impl.cq.ConquestArea;
import net.tv90.bfmccore.game.impl.cq.FrontLineConquestArea;
import net.tv90.bfmccore.game.impl.cq.IVehicleSpawnConquestArea;
import net.tv90.bfmccore.game.view.MapCoordConverter;
import net.tv90.bfmccore.util.area.Area;
import net.tv90.bfmccore.util.file.FileUtils;
import net.tv90.bfmccore.util.vector.Vector3i;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static net.tv90.bfmccore.code.VehicleMenuAssets.resolveVehicleGroup;

public class GameResourceInitializer {

    public static void initializeAllGames() {
        GameManager.gameList_1.clear();
        GameManager.gameList_2.clear();
        GameManager.gameList_3.clear();
        GameManager.gameList_4.clear();
        File gameDir = new File(BFMCCore.PLUGIN_ROOT, "game");
        if (!gameDir.exists()) {
            gameDir.mkdirs();
            return;
        }
        File[] gameFiles = gameDir.listFiles((dir, name) ->
                name.toLowerCase().endsWith(".json")
        );
        if (gameFiles == null) {
            return;
        }
        Arrays.sort(gameFiles, (file1, file2) -> {
            String name1 = file1.getName();
            String name2 = file2.getName();
            return name1.compareToIgnoreCase(name2);
        });
        int successCount = 0;
        int failCount = 0;
        List<String> failMessages = new ArrayList<>();
        for (File gameFile : gameFiles) {
            try {
                GameResourceParam param = parseGameConfig(gameFile.getPath());
                buildGame(param);
                successCount++;
            } catch (Exception e) {
                failCount++;
                // 记录失败原因
                String reason = e.getMessage() != null ? e.getMessage() : e.toString();
                failMessages.add("文件【" + gameFile.getName() + "】加载失败：原因：" + reason);
            }
        }
        System.out.println("成功加载游戏文件数量：" + successCount + "，失败数量：" + failCount + "。");
        for (String msg : failMessages) {
            System.out.println(msg);
        }
    }

    private static List<Vector3i> toVector3i(GameResourceParam.PointListParam param){
        if(param == null) return null;
        List<Vector3i> pointList = new ArrayList<>();
        if(param.relativePath != null && param.listName != null) {
            pointList = FileUtils.readVector3iList(param.relativePath, param.listName);
        } else if(param.list != null) {
            for (List<Integer> list : param.list) {
                pointList.add(new Vector3i(list.get(0), list.get(1), list.get(2)));
            }
        }
        return pointList;
    }

    private static void buildGame(GameResourceParam param) throws Exception {
        try {
            // Create a new instance of the game base (could be FrontLineGame or another subclass)
            GameBase gameBase = param.gameType.getInstance();
            // 1. Initialize Areas/ConquestAreas
            List<ConquestArea> conquestAreas = new ArrayList<>();
            if (param.conquestAreaList != null) {
                for (GameResourceParam.ConquestAreaParam areaParam : param.conquestAreaList) {
                    Area area = areaParam.areaParam.type.getInstance(areaParam.areaParam.pointList, areaParam.areaParam.paramList);
                    List<Vector3i> firstFactionSpawnPoint = toVector3i(areaParam.firstFactionSpawnPoint);
                    List<Vector3i> firstFactionSpawnPointWhenCapturing = toVector3i(areaParam.firstFactionSpawnPointWhenCapturing);
                    List<Vector3i> secondFactionSpawnPoint = toVector3i(areaParam.secondFactionSpawnPoint);
                    List<Vector3i> secondFactionSpawnPointWhenCapturing = toVector3i(areaParam.secondFactionSpawnPointWhenCapturing);
                    ConquestArea conquestArea = areaParam.type.getInstance(area,
                            areaParam.index, areaParam.name, areaParam.canCapture,
                            firstFactionSpawnPoint, firstFactionSpawnPointWhenCapturing,
                            secondFactionSpawnPoint, secondFactionSpawnPointWhenCapturing);
                    conquestArea.setCaptureProperty(areaParam.maxTime, areaParam.secondPerTicket);
                    conquestArea.setCaptureState(areaParam.currentFaction, ConquestArea.ConquestAreaState.valueOf(areaParam.currentState));
                    if (param.mapRelativeCood == null) {
                        // 没有配置相对坐标时，使用固定坐标
                        conquestArea.setConquestAreaButtonPosition(areaParam.imagePosX, areaParam.imagePosY, areaParam.imageWidth, areaParam.imageHeight);
                    } else {
                        // 获取配置的世界坐标和 UI 尺寸
                        int x1 = param.mapRelativeCood.get(0).get(0);
                        int z1 = param.mapRelativeCood.get(0).get(1);
                        int x2 = param.mapRelativeCood.get(1).get(0);
                        int z2 = param.mapRelativeCood.get(1).get(1);
                        int relX = 854;
                        int relZ = 445;
                        // 地图在 UI 中的宽高，用于计算比例
                        int uiMapWidth  = 791;//param.mapRelativeCood.get(2).get(0);
                        int uiMapHeight = 400;//param.mapRelativeCood.get(2).get(1);
                        // 计算区域中心的世界坐标 (centerX, centerZ)
                        int centerX = 0, centerZ = 0;
                        if (areaParam.areaParam.type == EnumAreaType.RectangleArea3i) {
                            // 长方体区域：pointList 中存放两个三维向量（x,z和y）
                            List<Integer> p1 = areaParam.areaParam.pointList.get(0);
                            List<Integer> p2 = areaParam.areaParam.pointList.get(1);
                            // 取 x,z 的平均作为中心
                            centerX = (p1.get(0) + p2.get(0)) / 2;
                            centerZ = (p1.get(2) + p2.get(2)) / 2;
                        } else if (areaParam.areaParam.type == EnumAreaType.CircleArea3i) {
                            // 圆形区域：pointList 中一个二维向量表示圆心 (x,z)
                            List<Integer> center = areaParam.areaParam.pointList.get(0);
                            centerX = center.get(0);
                            centerZ = center.get(1);
                        } else {
                            // 多边形区域：pointList 存放 n 个二维向量 (x,z)，取平均位置作为中心
                            long sumX = 0, sumZ = 0;
                            for (List<Integer> p : areaParam.areaParam.pointList) {
                                sumX += p.get(0);
                                sumZ += p.get(1);
                            }
                            centerX = (int) (sumX / areaParam.areaParam.pointList.size());
                            centerZ = (int) (sumZ / areaParam.areaParam.pointList.size());
                        }
                        float percentX, percentZ;
                        if (x1 < x2 && z1 < z2) {
                            // 未旋转，北朝上
                            percentX = (float) (centerX - x1) / (x2 - x1);
                            percentZ = (float) (centerZ - z1) / (z2 - z1);
                        } else if (x1 > x2 && z1 > z2) {
                            // 180° 旋转，北朝下
                            percentX = (float) (x1 - centerX) / (x1 - x2);
                            percentZ = (float) (z1 - centerZ) / (z1 - z2);
                        } else if (x1 > x2 && z1 < z2) {
                            // 顺时针旋转 90°：UI 水平方向对应世界南北，UI 垂直方向对应世界东西并取反
                            percentX = (float) (centerZ - z1) / (z2 - z1);
                            percentZ = (float) (x1 - centerX) / (x1 - x2);
                        } else {
                            // 逆时针旋转 90°：UI 水平方向对应世界南北并取反，UI 垂直方向对应世界东西
                            percentX = (float) (z1 - centerZ) / (z1 - z2);
                            percentZ = (float) (centerX - x1) / (x2 - x1);
                        }
                        // 将百分比限定在 [0,1]，防止越界
                        percentX = Math.max(0, Math.min(1, percentX));
                        percentZ = Math.max(0, Math.min(1, percentZ));
                        // 按照原来的方式转换成屏幕坐标并加上偏移
                        int x = Math.round(percentX * uiMapWidth  - areaParam.imageWidth  / 2f);
                        int z = Math.round(percentZ * uiMapHeight - areaParam.imageHeight / 2f);
                        x += (relX - uiMapWidth) / 2;
                        z += (relZ - uiMapHeight) / 2;
                        // 设置标点位置和大小，让区域标点在图片中心显示
                        conquestArea.setConquestAreaButtonPosition(x, z, areaParam.imageWidth, areaParam.imageHeight);
                    }
                    // 2. Initialize spawn points, vehicle groups, etc.
                    // Add additional logic here based on the `GameResourceParam`
                    if (conquestArea instanceof IVehicleSpawnConquestArea) {
                        IVehicleSpawnConquestArea vsCa = (IVehicleSpawnConquestArea) conquestArea;
                        if (areaParam.hasLight) {
                            vsCa.setHasLight();
                            vsCa.setFirstLightSpawnPoint(toVector3i(areaParam.firstLightSpawnPoint));
                            vsCa.setSecondLightSpawnPoint(toVector3i(areaParam.secondLightSpawnPoint));
                            vsCa.setFirstLightVehicleGroup(resolveVehicleGroup(areaParam.firstLightVehicleGroup));
                            vsCa.setSecondLightVehicleGroup(resolveVehicleGroup(areaParam.secondLightVehicleGroup));
                        }

                        if (areaParam.hasTank) {
                            vsCa.setHasTank();
                            vsCa.setFirstTankSpawnPoint(toVector3i(areaParam.firstTankSpawnPoint));
                            vsCa.setSecondTankSpawnPoint(toVector3i(areaParam.secondTankSpawnPoint));
                            vsCa.setFirstTankVehicleGroup(resolveVehicleGroup(areaParam.firstTankVehicleGroup));
                            vsCa.setSecondTankVehicleGroup(resolveVehicleGroup(areaParam.secondTankVehicleGroup));
                        }

                        if (areaParam.hasAA) {
                            vsCa.setHasAA();
                            vsCa.setFirstAASpawnPoint(toVector3i(areaParam.firstAASpawnPoint));
                            vsCa.setSecondAASpawnPoint(toVector3i(areaParam.secondAASpawnPoint));
                            vsCa.setFirstAAVehicleGroup(resolveVehicleGroup(areaParam.firstAAVehicleGroup));
                            vsCa.setSecondAAVehicleGroup(resolveVehicleGroup(areaParam.secondAAVehicleGroup));
                        }

                        if (areaParam.hasHeli) {
                            vsCa.setHasHeli();
                            vsCa.setFirstHeliSpawnPoint(toVector3i(areaParam.firstHeliSpawnPoint));
                            vsCa.setSecondHeliSpawnPoint(toVector3i(areaParam.secondHeliSpawnPoint));
                            vsCa.setFirstHeliVehicleGroup(resolveVehicleGroup(areaParam.firstHeliVehicleGroup));
                            vsCa.setSecondHeliVehicleGroup(resolveVehicleGroup(areaParam.secondHeliVehicleGroup));
                        }

                        if (areaParam.hasTransHeli) {
                            vsCa.setHasTransHeli();
                            vsCa.setFirstTransHeliSpawnPoint(toVector3i(areaParam.firstTransHeliSpawnPoint));
                            vsCa.setSecondTransHeliSpawnPoint(toVector3i(areaParam.secondTransHeliSpawnPoint));
                            vsCa.setFirstTransHeliVehicleGroup(resolveVehicleGroup(areaParam.firstTransHeliVehicleGroup));
                            vsCa.setSecondTransHeliVehicleGroup(resolveVehicleGroup(areaParam.secondTransHeliVehicleGroup));
                        }

                        if (areaParam.hasJet) {
                            vsCa.setHasJet();
                            vsCa.setFirstJetSpawnPoint(toVector3i(areaParam.firstJetSpawnPoint));
                            vsCa.setSecondJetSpawnPoint(toVector3i(areaParam.secondJetSpawnPoint));
                            vsCa.setFirstJetVehicleGroup(resolveVehicleGroup(areaParam.firstJetVehicleGroup));
                            vsCa.setSecondJetVehicleGroup(resolveVehicleGroup(areaParam.secondJetVehicleGroup));
                        }

                        if (areaParam.hasAtkJet) {
                            vsCa.setHasAtkJet();
                            vsCa.setFirstAtkJetSpawnPoint(toVector3i(areaParam.firstAtkJetSpawnPoint));
                            vsCa.setSecondAtkJetSpawnPoint(toVector3i(areaParam.secondAtkJetSpawnPoint));
                            vsCa.setFirstAtkJetVehicleGroup(resolveVehicleGroup(areaParam.firstAtkJetVehicleGroup));
                            vsCa.setSecondAtkJetVehicleGroup(resolveVehicleGroup(areaParam.secondAtkJetVehicleGroup));
                        }

                        if (areaParam.hasFac) {
                            vsCa.setHasFac();
                            vsCa.setFirstFacSpawnPoint(toVector3i(areaParam.firstFacSpawnPoint));
                            vsCa.setSecondFacSpawnPoint(toVector3i(areaParam.secondFacSpawnPoint));
                            vsCa.setFirstFacVehicleGroup(resolveVehicleGroup(areaParam.firstFacVehicleGroup));
                            vsCa.setSecondFacVehicleGroup(resolveVehicleGroup(areaParam.secondFacVehicleGroup));
                        }
                    }
                    conquestAreas.add(conquestArea);
                }
            }

            // Set up the game instance
            String gameTypeName = param.gameType_Lang == null ? param.gameType.name_lang : param.gameType_Lang;
            if (gameBase instanceof ConquestGame) {
                gameBase.initGameSource(
                        param.worldName, gameTypeName, param.firstFaction, param.secondFaction,
                        new Vector3i(param.mainSpawnPoint.get(0), param.mainSpawnPoint.get(1), param.mainSpawnPoint.get(2)),
                        new Vector3i(param.firstFactionSpawnPoint.get(0), param.firstFactionSpawnPoint.get(1), param.firstFactionSpawnPoint.get(2)),
                        new Vector3i(param.secondFactionSpawnPoint.get(0), param.secondFactionSpawnPoint.get(1), param.secondFactionSpawnPoint.get(2)),
                        conquestAreas
                );
                if (gameBase instanceof FrontLineGame) {
                    List<FrontLineConquestArea> flAreas = new ArrayList<>();
                    for (ConquestArea area : conquestAreas) {
                        if (area instanceof FrontLineConquestArea) {
                            flAreas.add((FrontLineConquestArea) area);
                        }
                    }
                    FrontLineConquestArea.toLinkedList(flAreas);
                }
            } else if (gameBase instanceof TDMGame) {
                gameBase.initGameSource(
                        param.worldName, gameTypeName, param.firstFaction, param.secondFaction,
                        new Vector3i(param.mainSpawnPoint.get(0), param.mainSpawnPoint.get(1), param.mainSpawnPoint.get(2)),
                        new Vector3i(param.firstFactionSpawnPoint.get(0), param.firstFactionSpawnPoint.get(1), param.firstFactionSpawnPoint.get(2)),
                        new Vector3i(param.secondFactionSpawnPoint.get(0), param.secondFactionSpawnPoint.get(1), param.secondFactionSpawnPoint.get(2)),
                        toVector3i(param.firstFactionSpawnPointList),
                        toVector3i(param.secondFactionSpawnPointList)
                );
            }

            // Set other game properties
            gameBase.setTime(param.maxTime);
            gameBase.setTicket(param.maxTicket);
            gameBase.setMapName_Lang(param.mapName);
            gameBase.setGameType(param.gameType);

            // Max AI, cooldowns, and other specific properties
            gameBase.maxAi = param.maxAi;

            gameBase.setMaxLightVehicleNum(param.maxLightVehicleNum);
            gameBase.setMaxTankNum(param.maxTankNum);
            gameBase.setMaxAANum(param.maxAANum);
            gameBase.setMaxHeliNum(param.maxHeliNum);
            gameBase.setMaxTransHeliNum(param.maxTransHeliNum);
            gameBase.setMaxJetNum(param.maxJetNum);
            gameBase.setMaxAtkJetNum(param.maxAtkJetNum);
            gameBase.setMaxFacNum(param.maxFacNum);

            gameBase.lightVehicleCooldownTime = param.lightVehicleCooldownTime;
            gameBase.tankCooldownTime = param.tankCooldownTime;
            gameBase.aaCooldownTime = param.aaCooldownTime;
            gameBase.heliCooldownTime = param.heliCooldownTime;
            gameBase.transHeliCooldownTime = param.transHeliCooldownTime;
            gameBase.jetCooldownTime = param.jetCooldownTime;
            gameBase.atkJetCooldownTime = param.atkJetCooldownTime;
            gameBase.facCooldownTime = param.facCooldownTime;

            if (param.generateMenu) {
                gameBase.generateMenu();
            }

            if (param.mapRelativeCood != null) {
                gameBase.mapCoordConverter = new MapCoordConverter();
                int x1 = param.mapRelativeCood.get(0).get(0);
                int z1 = param.mapRelativeCood.get(0).get(1);
                int x2 = param.mapRelativeCood.get(1).get(0);
                int z2 = param.mapRelativeCood.get(1).get(1);
                int uiMapWidth = 791;
                int uiMapHeight = 400;
                int relWidth = 854;
                int relHeight = 445;
                gameBase.mapCoordConverter.setMapCoordinateReference(x1, z1, x2, z2, uiMapWidth, uiMapHeight, relWidth, relHeight);
            }

            // Add game instance to various game lists
            for (int index : param.gamePoolIndex) {
                if (index == 1) {
                    GameManager.gameList_1.add(gameBase);
                }
                if (index == 2) {
                    GameManager.gameList_2.add(gameBase);
                }
                if (index == 3) {
                    GameManager.gameList_3.add(gameBase);
                }
                if (index == 4) {
                    GameManager.gameList_4.add(gameBase);
                }
            }
        } catch (NullPointerException e) {
            throw new Exception("加载json文件到游戏实例错误: 发生空指针异常，" + e.getMessage());
        } catch (IndexOutOfBoundsException e) {
            throw new Exception("加载json文件到游戏实例错误: 发生容器索引越界异常，" + e.getMessage());
        } catch (Exception e) {
            throw new Exception("加载json文件到游戏实例错误: " + e.getMessage());
        }
    }

    /**
     * 解析json配置到GameResourceParam对象
     */
    private static GameResourceParam parseGameConfig(String filePath) throws FileNotFoundException {
        Gson gson = new Gson();
        try (InputStreamReader fileReader = new InputStreamReader(Files.newInputStream(Paths.get(filePath)), StandardCharsets.UTF_8)) {
            Type gameResourceParamType = new TypeToken<GameResourceParam>() {}.getType();
            return gson.fromJson(fileReader, gameResourceParamType);
        } catch (Exception e) {
            throw new FileNotFoundException("格式错误，无法读取json文件: " + filePath);
        }
    }

    public static void init() {
        VehicleMenuAssets.init();
        initializeAllGames();
    }
}
